package com.zhuxulin.midi.event.meta;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.zhuxulin.midi.event.MidiEvent;
import com.zhuxulin.midi.util.ReadVarLen;

/**
 * FF 54 event
 * 
 * @author ZhuXulin
 * 
 */
public class SmpteOffset extends MetaEvent {

	public static final int FRAME_RATE_24 = 0;
	public static final int FRAME_RATE_25 = 1;
	public static final int FRAME_RATE_30_DROP = 2;
	public static final int FRAME_RATE_30 = 3;

	private FrameRate mFrameRate;
	private int mHours;
	private int mMinutes;
	private int mSeconds;
	private int mFrames;
	private int mSubFrames;

	public SmpteOffset(long tick, long delta, FrameRate fps, int hour, int min,
			int sec, int fr, int subfr) {
		super(tick, delta, MetaEvent.SMPTE_OFFSET, new ReadVarLen(5));

		mFrameRate = fps;
		mHours = hour;
		mMinutes = min;
		mSeconds = sec;
		mFrames = fr;
		mSubFrames = subfr;
	}

	public void setFrameRate(FrameRate fps) {
		mFrameRate = fps;
	}

	public FrameRate getFrameRate() {
		return mFrameRate;
	}

	public void setHours(int h) {
		mHours = h;
	}

	public int getHours() {
		return mHours;
	}

	public void setMinutes(int m) {
		mMinutes = m;
	}

	public int getMinutes() {
		return mMinutes;
	}

	public void setSeconds(int s) {
		mSeconds = s;
	}

	public int getSeconds() {
		return mSeconds;
	}

	public void setFrames(int f) {
		mFrames = f;
	}

	public int getFrames() {
		return mFrames;
	}

	public void setSubFrames(int s) {
		mSubFrames = s;
	}

	public int getSubFrames() {
		return mSubFrames;
	}

	@Override
	protected int getEventSize() {
		return 8;
	}

	@Override
	public void writeToFile(OutputStream out) throws IOException {
		super.writeToFile(out);

		out.write(5);
		out.write(mHours);
		out.write(mMinutes);
		out.write(mSeconds);
		out.write(mFrames);
		out.write(mSubFrames);
	}

	@Override
	public byte[] getCmd() {
		cmd = new byte[] { (byte) 0xFF, 0x54, 0x05, (byte) mHours,
				(byte) mMinutes, (byte) mSeconds, (byte) mFrames,
				(byte) mSubFrames };
		return cmd;
	}

	public static SmpteOffset parseSmpteOffset(long tick, long delta,
			InputStream in) throws IOException {

		in.read(); // Size = 5
		int rrHours = in.read();

		int rr = rrHours >> 5;
		FrameRate fps = FrameRate.fromInt(rr);
		int hour = rrHours & 0x1F;

		int min = in.read();
		int sec = in.read();
		int frm = in.read();
		int sub = in.read();

		return new SmpteOffset(tick, delta, fps, hour, min, sec, frm, sub);
	}

	public enum FrameRate {
		FRAME_RATE_24(0x00), FRAME_RATE_25(0x01), FRAME_RATE_30_DROP(0x02), FRAME_RATE_30(
				0x03);

		public final int value;

		private FrameRate(int v) {
			value = v;
		}

		public static FrameRate fromInt(int val) {
			switch (val) {
			case 0:
				return FRAME_RATE_24;
			case 1:
				return FRAME_RATE_25;
			case 2:
				return FRAME_RATE_30_DROP;
			case 3:
				return FRAME_RATE_30;
			}
			return null;
		}
	}

	@Override
	public int compareTo(MidiEvent other) {

		if (mTick != other.getTick()) {
			return mTick < other.getTick() ? -1 : 1;
		}
		if (mDelta.getValue() != other.getDelta()) {
			return mDelta.getValue() < other.getDelta() ? 1 : -1;
		}

		if (!(other instanceof SmpteOffset)) {
			return 1;
		}
		return 0;
	}
}
